import java.util.*;
//states:
//before -> start exam
//middle -> finish
//finished -> restart, review
class Exam {
   public static final java.util.List<Card> allCards=
      Util.readExcel("red_bible.xls");

   final int startIndex, endIndex, total;
   final int numOfOptions; 
   int correctCount=0;
   final boolean isFlipped;
   final boolean isRestricted;
   Question currentQuestion=null;

   java.util.List<Question> questions=new ArrayList<Question>();
   int index=0;

   public Exam(String start, String end, 
         int o, boolean flip, boolean rt, boolean rnd) {
      this(findIndex(start), findIndexBackward(end), o, flip, rt, rnd);
   }
   public Exam(int s, int e,
         int o, boolean flip, boolean rt, boolean rnd) {
      this.startIndex=s;
      this.endIndex=e;
      this.total=this.endIndex-this.startIndex+1;
      this.numOfOptions=o;
      this.isFlipped=flip;
      this.isRestricted=rt;
      for(int i=startIndex; i<=endIndex; i++) {
         questions.add(new Question(this, i)); 
      }
      if(rnd) {
         Collections.shuffle(questions);
      }
      if(index>=questions.size()) throw new RuntimeException("empty set");
   }
   public void review() {
      if(correctCount==total) {
         throw new RuntimeException("no need to review");
      }
      final java.util.List<Question> wrongs=new ArrayList<Question>();
      for(int i=0; i<questions.size(); i++) {
         if(!questions.get(i).isCorrect) {
            wrongs.add(questions.get(i));
         }
      }
      questions=wrongs;
      for(int i=0; i<questions.size(); i++) {
         questions.get(i).isCorrect=false;
      }
      index=0;
      correctCount=0;
   }

   public Question getCurrentQuestion() {
      return currentQuestion;
   }
   public float getScore() { 
      return correctCount*100.0f/questions.size();
   }
   public boolean check(int ans) {
      final boolean correct=currentQuestion.check(ans);
      if(correct) {
         correctCount++;
      }   
      return correct;
   }
   public boolean hasNext() { 
      return index<questions.size(); 
   }
   public Question next() {
      currentQuestion=questions.get(index++);
      return currentQuestion;
   }

   public static int findIndex(String key) {
      for(int i=0; i<allCards.size(); i++) {
         if(allCards.get(i).getFront().startsWith(key)) {
            return i;
         }
      }
      return -1;
   }
   public static int findIndexBackward(String key) {
      for(int i=allCards.size()-1; i>=0; i--) {
         if(allCards.get(i).getFront().startsWith(key)) {
            return i;
         }
      }
      return -1;
   }
}

class Question {
   public final int problem;
   public final int[] options;
   final Exam exam;
   final int answer;
   boolean isCorrect;

   public Question(Exam e, int index) {
      exam=e;
      problem=index;

      int optionIndex=answer=Util.random.nextInt(exam.numOfOptions);

      options=new int[exam.numOfOptions];
      options[optionIndex++]=index;

      for(int i=0; i<exam.numOfOptions-1; i++) {
         if(!exam.isRestricted) {
            options[optionIndex%exam.numOfOptions]=
               Util.random.nextInt(Exam.allCards.size());
         } else {
            options[optionIndex%exam.numOfOptions]=
               exam.startIndex+Util.random.nextInt(exam.total);
         }

         optionIndex++;
         //>>> eliminate duplicate entry
      }
   }
   /*
   public String getPrompt() {
      return Exam.allCards.get(problem).getFront();
   }
   public String getChoice(int index) {
      return Exam.allCards.get(choiceIndices[index]).getBack();
   }
   */
   public String getChoicePrompt(int index) {
      return Exam.allCards.get(options[index]).getFront();
   }
   public boolean check(int ans) {
      isCorrect=(ans==answer);
      return isCorrect;
   }
}
